﻿using System;
using System.Diagnostics.Contracts;

namespace O1.Data.Traversal
{
    [ContractVerification(true)]
    public sealed class CellObserver
    {
        private readonly Filter filter;

        public CellObserver(Filter filter)
        {
            Contract.Requires<ArgumentNullException>(filter != null);
            this.filter = filter;
        }

        public ObservationInterests ObservationState { get; set; }

        public void OnCellVersion(CellVersion version)
        {
            this.ObservationState = this.filter.CheckVersion(version);
        }

        public void OnBeginVertex(CellAddress value)
        {
            this.ObservationState = this.filter.StartVertex(value);
        }

        public void OnEndVertex()
        {
            this.ObservationState = this.filter.EndVertex(this.ObservationState);
        }

        public void OnBeginInEdge(Edge value)
        {
            this.ObservationState = this.filter.StartEdge(value, EdgeDirections.Inbound);
        }

        public void OnBeginOutEdge(Edge value)
        {
            this.ObservationState = this.filter.StartEdge(value, EdgeDirections.Outbound);
        }

        public void OnEndEdge()
        {
            this.ObservationState = this.filter.EndEdge(this.ObservationState);
        }

        public void OnProperty(DecimalProperty value)
        {
            if (this.filter.PropertyInterest.HasFlag(PropertyInterests.Decimal))
            {
                this.ObservationState = this.filter.Evaluate(value);
            }
        }

        public void OnProperty(DateProperty value)
        {
            if (this.filter.PropertyInterest.HasFlag(PropertyInterests.Date))
            {
                this.ObservationState = this.filter.Evaluate(value);
            }
        }

        public void OnProperty(DateTimeProperty value)
        {
            if (this.filter.PropertyInterest.HasFlag(PropertyInterests.DateTime))
            {
                this.ObservationState = this.filter.Evaluate(value);
            }
        }

        public void OnProperty(Int16Property value)
        {
            if (this.filter.PropertyInterest.HasFlag(PropertyInterests.Int16))
            {
                this.ObservationState = this.filter.Evaluate(value);
            }
        }

        public void OnProperty(Int32Property value)
        {
            if (this.filter.PropertyInterest.HasFlag(PropertyInterests.Int32))
            {
                this.ObservationState = this.filter.Evaluate(value);
            }
        }

        public void OnProperty(Int64Property value)
        {
            if (this.filter.PropertyInterest.HasFlag(PropertyInterests.Int64))
            {
                this.ObservationState = this.filter.Evaluate(value);
            }
        }

        public void OnProperty(StringProperty value)
        {
            if (this.filter.PropertyInterest.HasFlag(PropertyInterests.String))
            {
                this.ObservationState = this.filter.Evaluate(value);
            }
        }

        public void OnProperty(HashProperty value)
        {
            if (this.filter.PropertyInterest.HasFlag(PropertyInterests.Hash))
            {
                this.ObservationState = this.filter.Evaluate(value);
            }
        }

        [ContractInvariantMethod]
        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "Required for code contracts.")]
        private void ObjectInvariant()
        {
            Contract.Invariant(this.filter != null);
        }
    }
}